package com.only4play.common.utils;

import java.security.SecureRandom;
import java.util.UUID;

/**
 * 通用（字符串、数字等）工具类
 *
 * @author liyuncong
 * @date 2023/11/15 15:21
 **/
public class CommonUtils {

    private static final String DEFAULT_LOWER_CHAR_STRING = "abcdefghijklmnopqrstuvwxyz";
    private static final String DEFAULT_UPPER_CHAR_STRING = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final String DEFAULT_NUMBER_CHAR_STRING = "0123456789";
    private static final String DEFAULT_SPECIAL_CHAR_STRING = "~!@#$%^&*()_+={}[]<>|?,.:;'`";

    public static String uuid() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * 生成指定长度随机字符串
     *
     * @param len 需生成随机串长度
     * @return 生成结果
     */
    public static String randomString(int len) {
        int l = (int) Math.floor((double) (len * 26) / 91);
        int u = (int) Math.floor((double) (len * 26) / 91);
        int s = (int) Math.floor((double) (len * 29) / 91);
        int n = len - l - u - s;
        return randomString(len, l, u, n, s);
    }

    /**
     * 生成指定长度随机字符串
     *
     * @param len               需生成随机串长度
     * @param lowerCharWeight   小写字母权重
     * @param upperCharWeight   大写字母权重
     * @param numberCharWeight  数字字母权重
     * @param specialCharWeight 特殊字符权重
     * @return 生成结果
     */
    public static String randomString(
        int len, int lowerCharWeight, int upperCharWeight, int numberCharWeight, int specialCharWeight
    ) {
        if (len < 4) {
            throw new IllegalArgumentException("The length of the generated random string must be greater than four.");
        }
        if (!checkWeight(len, lowerCharWeight, upperCharWeight, numberCharWeight, specialCharWeight)) {
            throw new IllegalArgumentException("The weight of the generated random string out of range or not enough.");
        }
        String result;
        StringBuilder sb = new StringBuilder();
        char[] lowerCharStringCharArray = DEFAULT_LOWER_CHAR_STRING.toCharArray();
        for (int x = 0; x < lowerCharWeight; ++x) {
            sb.append(lowerCharStringCharArray[getRandomNumber(lowerCharStringCharArray.length)]);
        }
        char[] upperCharStringCharArray = DEFAULT_UPPER_CHAR_STRING.toCharArray();
        for (int x = 0; x < upperCharWeight; ++x) {
            sb.append(upperCharStringCharArray[getRandomNumber(upperCharStringCharArray.length)]);
        }
        char[] numberCharStringCharArray = DEFAULT_NUMBER_CHAR_STRING.toCharArray();
        for (int x = 0; x < numberCharWeight; ++x) {
            sb.append(numberCharStringCharArray[getRandomNumber(numberCharStringCharArray.length)]);
        }
        char[] specialCharStringCharArray = DEFAULT_SPECIAL_CHAR_STRING.toCharArray();
        for (int x = 0; x < specialCharWeight; ++x) {
            sb.append(specialCharStringCharArray[getRandomNumber(specialCharStringCharArray.length)]);
        }
        result = upsets(sb.toString());
        if (!check(result)) {
            result = randomString(len, lowerCharWeight, upperCharWeight, numberCharWeight, specialCharWeight);
        }
        return result;
    }

    /**
     * @param bound
     * @return
     */
    public static int getRandomNumber(int bound) {
        final String algorithm = "NativePRNG";
        try {
            SecureRandom instance = SecureRandom.getInstance(algorithm);
            return instance.nextInt(bound);
        } catch (Exception exception) {
            throw new IllegalArgumentException();
        }
    }

    /**
     * 校验权重
     *
     * @param len               需生成随机串长度
     * @param lowerCharWeight   小写字母权重
     * @param upperCharWeight   大写字母权重
     * @param numberCharWeight  数字字母权重
     * @param specialCharWeight 特殊字符权重
     * @return 校验结果
     */
    private static boolean checkWeight(
        int len, int lowerCharWeight, int upperCharWeight, int numberCharWeight, int specialCharWeight
    ) {
        int min = 1;
        int max = len - 3;
        return (min <= lowerCharWeight && lowerCharWeight <= max)
            && (min <= upperCharWeight && upperCharWeight <= max)
            && (min <= numberCharWeight && numberCharWeight <= max)
            && (min <= specialCharWeight && specialCharWeight <= max)
            && (len == (lowerCharWeight + upperCharWeight + numberCharWeight + specialCharWeight));
    }

    /**
     * 强制校验是包含大写字母、小写字母、特殊字符、数字
     *
     * @param content 被校验字符串
     * @return 校验结果
     */
    public static boolean check(String content) {
        String pattern1 = ".*[a-z]+.*";
        String pattern2 = ".*[A-Z]+.*";
        String pattern3 = ".*[0-9]+.*";
        String pattern4 = ".*[~!@#$%^&*()_+{}|<>?]+.*";
        return (content.matches(pattern1) && content.matches(pattern2)
            && content.matches(pattern3) && content.matches(pattern4));
    }

    /**
     * 随机打乱字符串
     *
     * @param content 原字符串
     * @return 打乱后的字符串
     */
    public static String upsets(String content) {
        char[] charArr = content.toCharArray();
        for (int i = 0; i < charArr.length; i++) {
            int index = getRandomNumber(charArr.length);
            char temp = charArr[i];
            charArr[i] = charArr[index];
            charArr[index] = temp;
        }
        return String.copyValueOf(charArr);
    }
}
